#============================================================
#	Spring
#============================================================
# @datetime: 2022-5-23 01:04:20
#============================================================
tool
extends Node
class_name Spring

signal arrived


export var host : NodePath 
onready var _host : KinematicBody2D = get_node(host)
export var speed : float = 0.0 setget set_speed
export var arrive_distance: float = 10.0 setget set_arrive_distance


var _proxy : ProxyMoveBase
var _arrive_distance_squared : float


#============================================================
#   Set/Get
#============================================================
func get_host() -> KinematicBody2D:
	if _host == null and host != "":
		_host = get_node(host) as KinematicBody2D
	update_configuration_warning()
	return _host

func set_speed(value: float) -> void:
	speed = value
	update_configuration_warning()

func set_arrive_distance(value: float) -> void:
	arrive_distance = value
	_arrive_distance_squared = pow(arrive_distance, 2)
	update_configuration_warning()


#============================================================
#   内置
#============================================================
func _ready():
	set_physics_process(false)
	set_arrive_distance(arrive_distance)

func _get_configuration_warning():
	if host == "":
		return "没有设置控制的宿主，使用将不会生效，请设置“host”属性"
	if speed == 0.0:
		return "没有设置移动速度，将不会移动！"
	if arrive_distance == 0.0:
		return "到达位置的判定距离过小，可能会有抖动问题"
	return ""

func _physics_process(delta):
	_proxy.move(speed)
	if _proxy.get_distance_squared() <= _arrive_distance_squared:
		emit_signal("arrived")
		stop()
	printt(_proxy.get_distance_squared(), _arrive_distance_squared)


#============================================================
#   自定义
#============================================================
##  开始冲刺到目标位置
## @target  
func start(target) -> void:
	assert(get_host() != null, "没有设置宿主")
	
	if target is Vector2:
		_proxy = ToPosition.new(get_host(), target)
		set_physics_process(true)
	elif target is Node2D:
		_proxy = ToNode2D.new(get_host(), target)
		set_physics_process(true)
	else:
		assert(false, "必须是 Vector2 或 Node2D 及其子类型！")

##  停止 
func stop() -> void:
	set_physics_process(false)



#============================================================
#   代理对象移动
#============================================================
class ProxyMoveBase:
	var target
	var host : KinematicBody2D
	
	func get_distance() -> float:
		return INF
	
	func get_distance_squared() -> float:
		return INF
	
	func move(speed: float):
		pass
	


## 移动到目标位置
class ToPosition:
	extends ProxyMoveBase
	
	var direction: Vector2
	
	func _init(host: KinematicBody2D, target: Vector2):
		self.host = host
		self.target = target
		direction = host.global_position.direction_to(target)
	
	func move(speed):
		host.move_and_slide(direction * speed)
	
	func get_distance() -> float:
		return host.global_position.distance_to(target)
	
	func get_distance_squared() -> float:
		return host.global_position.distance_squared_to(target)


## 移动到目标节点
class ToNode2D:
	extends ProxyMoveBase
	
	var direction : Vector2
	
	func _init(host: KinematicBody2D, target: Node2D):
		self.host = host
		self.target = target
	
	func move(speed):
		direction = host.global_position.direction_to(target.global_position)
		host.move_and_slide(direction * speed)
	
	func get_distance() -> float:
		return host.global_position.distance_to(target.global_position)
	
	func get_distance_squared() -> float:
		return host.global_position.distance_squared_to(target.global_position)


